<!--
 * @Author: panda
 * @Date: 2022-05-18 10:28
 * @Description: 上传视频组件
-->
<template>
  <el-upload
    class="upload-demo"
    drag
    action="#"
    :limit="limit"
    accept=".mp4,.mov,.avi"
    :http-request="httpRequest"
    :on-success="onUploadSuccess"
    :on-remove="handleRemove"
    :on-error="onUploadError"
    :on-exceed="handleExceed"
    :on-progress="onUploadProgress"
    :on-preview="handlePictureCardPreview"
    :before-upload="onBeforeUpload"
    :file-list="videoList!==undefined?videoList:[]"
  >
    <el-icon class="el-icon--upload">
      <upload-filled />
    </el-icon>
    <div class="el-upload__text">
      把文件拖到这里或 <em>点击上传</em>
    </div>

    <template #tip>
      <div class="el-upload__tip">
        mp4/avi 文件小于100MB, 点击下方文件名预览
      </div>
    </template>
  </el-upload>
  <el-space style="display: none">
    <video
      :src="emitVideo.videoUrl" controls="controls"
      crossorigin="anonymous"
      id="videoPlay">您的浏览器不支持视频播放
    </video>
    <canvas id="canvas" style="display: block"></canvas>
  </el-space>
  <br />
  <el-dialog v-model="dialogVisible">
    <video style="width: 100%;height: 100%;" :src="dialogImageUrl" controls="controls" crossorigin="anonymous">
      您的浏览器不支持视频播放
    </video>
  </el-dialog>
</template>

<script lang="ts">
import {UploadFilled} from '@element-plus/icons-vue'
import {defineComponent, nextTick, reactive, ref, watch} from "vue";
import {
  ElMessageBox,
  UploadFile,
  UploadProps,
  UploadRawFile,
  UploadUserFile
} from "element-plus/es";
import { upload, uploadCover} from "@/utils/cos";
import {UploadProgressEvent} from "element-plus/es/components/upload/src/upload";

export default defineComponent({
  components: {UploadFilled},

  props: {
    videoUrl: String,
  },
  // emit视频链接给上传视频页面
  emits: ['videoUrl'],
  setup(props, context) {
    //文件数量限制
    const limit = ref(1)
    //文件大小限制
    const limitSize = ref(200)
    //文件名，为删除作准备 TODO
    const fileKey = ref('')

    const dialogImageUrl = ref('')
// 放大图片弹窗是否显示
    const dialogVisible = ref(false)

    //上传视频绑定列表
    let videoList = ref<UploadUserFile[]>([])
    //上传视频方法，请求
    const httpRequest = upload
    //视频信息，视频url，视频封面，视频大小，视频时长，视屏长宽
    const emitVideo = reactive({
      videoUrl: '',
      cover: '',
      videoSize: 0,
      duration: 0,
      videoWidth: 0,
      videoHeight: 0
    })
    // 删除视频
    const handleRemove: UploadProps['onRemove'] = () => {
      ElMessageBox.confirm(
        '资源将被永久删除，确认删除？',
        '警告',
        {
          confirmButtonText: '删除',
          cancelButtonText: '取消',
          type: 'warning',
        }
      ).then(() => {
        // deleteObject(fileKey.value)
      })
    }

    // watch父组件传过来的视频封面链接
    watch(() => props.videoUrl, (cur) => {
      console.log(cur)
      const key = cur!.toString().split("/")
      fileKey.value = key[3] + '/' + key[4]
      //删掉默认图片列表空链接
      videoList.value.pop()
      //将视频封面加入图片列表
      videoList.value.push({name: fileKey.value, url: cur})
    })


    // 图片预览
    const handlePictureCardPreview = (file: UploadFile) => {
      dialogImageUrl.value = file.url!
      dialogVisible.value = true
    }

    // base64转图片方法 copy
    function base64ToBlob(urlData: string, type = "image/png"): Blob {
      let arr = urlData.split(',');
      let mime = arr[0].match(/:(.*?);/)![1] || type;
      // 去掉url的头，并转化为byte
      let bytes = window.atob(arr[1]);
      // 处理异常,将ascii码小于0的转换为大于0
      let ab = new ArrayBuffer(bytes.length);
      // 生成视图（直接针对内存）：8位无符号整数，长度1个字节
      let ia = new Uint8Array(ab);
      for (let i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
      }
      return new Blob([ab], {
        type: mime
      });
    }

    const onUploadProgress = (evt: UploadProgressEvent) => {
      console.log(evt)
    }
    // 上传成功回调
    const onUploadSuccess: UploadProps['onSuccess'] = (
      response
    ) => {
      //返回地址保存数据库
      emitVideo.videoUrl = response
      //为删除视频作准备
      const key = response.toString().split("/")
      videoList.value.pop()
      videoList.value.push({name: key[4], url: emitVideo.videoUrl})
      fileKey.value = key[3] + '/' + key[4]
      //获取视频第一帧
      firstFrame()
    }
    //上传失败回调
    const onUploadError = (err: string) => {
      console.log(err);
      ElMessageBox.alert("请重新登陆再上传。", '错误提示', {
        confirmButtonText: '好的',
      })
    }
    //上传限制回调函数
    const handleExceed = () => {
      ElMessageBox.alert(`文件超过${limit.value}个！`, '错误提示', {
        confirmButtonText: '好的',
      })
    }
    //播放视频，获取图片第一帧 copy
    const loadVideo = (file: UploadRawFile) => {
      return new Promise((resolve, reject) => {
        const videoElem = document.createElement("video")
        const dataUrl = URL.createObjectURL(file);
        // 当前帧的数据是可用的
        videoElem.onloadeddata = () => {
          resolve(videoElem)
        };
        videoElem.onerror = () => {
          reject("video 后台加载失败")
        };
        // 设置 auto 预加载数据， 否则会出现截图为黑色图片的情况
        videoElem.setAttribute("preload", "auto")
        videoElem.src = dataUrl
      });
    }

    // 上传前回调，获取视频的尺寸，播放时长 copy
    const onBeforeUpload = (rawFile: UploadRawFile) => {
      return new Promise(async (resolve, reject) => {
        let fileName = rawFile.name || ""
        let ext = fileName.split(".")[fileName.split(".").length - 1]
        if (ext !== "mov" && ext !== "mp4" && ext !== "MP4" && ext !== "flv") {
          await ElMessageBox.alert('格式不正确!', '错误提示', {
            confirmButtonText: '好的',
          })
          return;
        } else {
          const size = rawFile.size / 1024 / 1024
          emitVideo.videoSize = size
          const isLimitM = size < limitSize.value
          let video: HTMLVideoElement
          video = await loadVideo(rawFile) as HTMLVideoElement
          emitVideo.duration = video.duration
          emitVideo.videoWidth = video.videoWidth
          emitVideo.videoHeight = video.videoHeight
          if (!isLimitM) {
            await ElMessageBox.alert(`上传视频大小不能超过${limitSize.value}MB!`, '错误提示', {
              confirmButtonText: '好的',
            })
            reject()
          }
        }
        resolve(() => {
        })
      })
    }

    //获取视屏第一帧作为封面 copy
    const firstFrame = () => {
      nextTick(() => {
        // 获取video节点
        const video = document.getElementById("videoPlay") as HTMLVideoElement;// 获取视频对象
        video.currentTime = 1 // 第一帧
        //创建canvas对象
        const canvas = document.getElementById('canvas') as HTMLCanvasElement // 获取 canvas 对象
        // 用视频第一帧做封面图片
        // video.src = url // url地址 url跟 视频流是一样的
        const ctx = canvas?.getContext('2d'); // 绘制2d
        video.oncanplay = () => {
          canvas.width = 320 // 获取视频宽度
          canvas.height = 200 // 获取视频高度
          // 利用canvas对象方法绘图
          ctx?.drawImage(video, 0, 0, 320, 200)
          // 转换成base64形式
          emitVideo.cover = canvas.toDataURL('image/png') // 将canvas导出成图片放入cover，截取后的视频封面
          uploadCover(base64ToBlob(emitVideo.cover)).then(
            res => {
              // 获取首图片链接
              emitVideo.cover = res as string
              //emit给上传视频页面
              context.emit('videoUrl', emitVideo)
            }
          );
        }
      })
    }

    return {
      handleRemove,
      onUploadSuccess,
      onUploadError, dialogVisible,
      handleExceed, dialogImageUrl,
      httpRequest,
      videoList, onUploadProgress, handlePictureCardPreview,
      limit,
      onBeforeUpload,
      emitVideo
    }
  }
})
</script>

<style>

/*上传组件大小*/
.el-upload-dragger {
  width: 500px;
  height: 200px;
}
</style>
